package org.gastomuito.client;

import java.util.ArrayList;

import org.gastomuito.shared.RegistroContabilDTO;
import org.gastomuito.shared.RelatorioDespesaAnualDTO;

import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasChangeHandlers;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;

public class ContaContabilController {

    private final ContabilidadeServiceAsync contabilidadeService;

    private final ReceitaDisplay receitaDisplay;

    private final DespesaDisplay despesaDisplay;

    private RegistroContabilDTO registro;

    public ContaContabilController(
            ContabilidadeServiceAsync contabilidadeService,
            ReceitaDisplay receitaView, DespesaDisplay despesaView) {
        this.contabilidadeService = contabilidadeService;
        this.receitaDisplay = receitaView;
        this.despesaDisplay = despesaView;
        this.registro = new RegistroContabilDTO();
        bind();
    }

    private void bind() {
        ChangeHandler repeticaHandler = new ChangeHandler() {
            @Override
            public void onChange(ChangeEvent event) {
                ListBox source = (ListBox) event.getSource();
                registro.setRepeticao(source.getItemText(source
                        .getSelectedIndex()));
            }
        };
        ValueChangeHandler<String> valorHandler =
                new ValueChangeHandler<String>() {
                    @Override
                    public void onValueChange(ValueChangeEvent<String> event) {
                        registro.setQuantidade(toDouble(event.getValue()));
                    }
                };
        despesaDisplay.getConta().addValueChangeHandler(
                new ValueChangeHandler<String>() {
                    @Override
                    public void onValueChange(ValueChangeEvent<String> event) {
                        registro.setContaCredito(event.getValue());
                    }
                });
        receitaDisplay.getRepeticao().addChangeHandler(repeticaHandler);
        despesaDisplay.getRepeticao().addChangeHandler(repeticaHandler);
        receitaDisplay.getValor().addValueChangeHandler(valorHandler);
        despesaDisplay.getValor().addValueChangeHandler(valorHandler);
        receitaDisplay.getSubmit().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                registrarReceita();
            }
        });
        despesaDisplay.getSubmit().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                registrarDespesa();
            }
        });
        contabilidadeService.listaContasPadrao(new AsyncCallback<String[]>() {
            @Override
            public void onFailure(Throwable caught) {
                caught.printStackTrace();
            }

            @Override
            public void onSuccess(String[] result) {
                ArrayList<String> sugestoesPadra =
                        new ArrayList<String>(result.length);
                for (String cc : result) {
                    despesaDisplay.getListaConta().add(cc);
                    sugestoesPadra.add(cc);
                }
                despesaDisplay.getListaConta().setDefaultSuggestionsFromText(
                        sugestoesPadra);
            }
        });
        despesaDisplay.setVisible(false);
        receitaDisplay.setVisible(true);

    }

    private void registrarReceita() {
        contabilidadeService.registrarReceita(registro,
                new AsyncCallback<RelatorioDespesaAnualDTO>() {
                    @Override
                    public void onSuccess(final RelatorioDespesaAnualDTO result) {
                        registro = new RegistroContabilDTO();
                        receitaDisplay.setVisible(false);
                        despesaDisplay.setVisible(true);
                    }

                    @Override
                    public void onFailure(Throwable caught) {
                        caught.printStackTrace();
                    }
                });
    }

    private void registrarDespesa() {
        contabilidadeService.registrarDespesa(registro,
                new AsyncCallback<RelatorioDespesaAnualDTO>() {
                    @Override
                    public void onSuccess(final RelatorioDespesaAnualDTO result) {
                        despesaDisplay.atualizar(result);
                        registro = new RegistroContabilDTO();
                    }

                    @Override
                    public void onFailure(Throwable caught) {
                        caught.printStackTrace();
                    }
                });
    }

    private double toDouble(String valor) {
        try {
            return NumberFormat.getDecimalFormat().parse(valor);
        } catch (NumberFormatException e) {
            return 0.0;
        }
    }

    public static interface ReceitaDisplay {

        HasValue<String> getValor();

        HasChangeHandlers getRepeticao();

        void setVisible(boolean v);

        HasClickHandlers getSubmit();
    }

    public static interface DespesaDisplay extends ReceitaDisplay {

        HasValue<String> getConta();

        MultiWordSuggestOracle getListaConta();

        void atualizar(RelatorioDespesaAnualDTO relatorio);

    }

}
